﻿using System;
using System.Runtime.InteropServices;
using Client;
using Microsoft.DirectX.Direct3D;

namespace Client
{
    /// <summary>
    /// Holds all the information about the current character being played.
    /// </summary>

    public class ActorInformation
    {
        public int ServerIndex;
        public short XX, YY;

        public byte Direction, Sex, Race, Hair, Armour, Weapon, Class;
        public short Appearance;
        public int Feature, State;
        public bool IsDead, IsSkeleton, DeleteActor, DeleteAfterFinished, IsVisible, HoldPlace;
        public string DescriptionUsername, FameName, Username;
        public int NameColour, Gold;
        // TAbility                                 // TODO: Convert TAbility
        public sbyte HitSpeed;
        public string[] Saying, SayingWidth;        // TODO: Give Better Variable Names - Array = ClientGlobals.MaxSay
        public uint SayTime;
        public int SayX, SayY, SayLineCount;

        public int ShiftX, ShiftY;
        public int Px, Py, Rx, Ry, DrawDownLevel, TargetX, TargetY, TargetServerIndex, HitterServerIndex;
        public int MagicNumber, CurrentEvent;
        public bool DigFragement, Throw;

        public int BodyOffset, HairOffset, WingOffset, WeaponOffset, WeaponEffectOffset;
        public bool UseMagic, HitEffect, UseEffect;
        public int HitEffectNumber, WaitForServerIndex, WaitForFeature, WaitForStatus;
        public uint WaitForMagicRequest;

        public int CurrentEffectFrame, SpellFrame;
        // CurrentMagic : TUseMagicInfo             // TODO: Convert TUseMagicInfo
        public int GenAniCount;                     // TODO: Get Better Variable Name
        public bool HealthBarOpen, InstanceOpenHealth;
        public int HealthBarOpenTime;
        public int HealthBarTime;

        public Texture BodyTexture;

        public bool IsGrouped, ReverseFrame, WarMode;
        public int WarModeTime, CurrentAction;
        public int CharatcerLight, MagicLight, RushDirection, WalkFrameDelay;

        public bool LockEndFrame;
        public int LastStruckTime, SendQueryUsernameTime, DeleteTime;

        public int MagicStruckSound, FootStepSound, StruckSound, StruckWeaponSound;
        public bool PlayRunSound;

        public int AppearSound, NormalSound, AttackSound, WeaponSound, ScreamSound, DieSound, DieSound2;
        public int MagicStartSound, MagicFireSound, MagicExploisionSound;

        public bool HighLevelEffect;
        public int FoodStickType;
        public byte TempState;

        protected int StartFrame, EndFrame, CurrentFrame, EffectStart, EffectFrame, EffectEnd;
        protected int EffectStartTime, EffectFrameTime, FrameTime, StartTime;
        protected int MaxTick, CurrentTick, MoveStep;
        protected bool MessageMuch;
        protected int StruckFrameTime;
        protected int CurrentDefaultFrame;
        protected int DefaultFrameTime;
        protected int DefaultFrameCount, SkipTick, SkipTick2;
        protected int SmoothMoveTime, GenAniCountTime, LoadSurfaceTime;

        protected int OldX, OldY, OldDirection, ActBeforeEx, ActBeforeEy, WPord;

        // NOTE: Originally RaceByPm
        public Object GetAnimations(int appr, int race)
        {
            switch (race)
            {
                case 9:
                    return new MonsterAction9();
                default:
                    return null;
            }
        }

        // NOTE: Returns The Monsters Image Library
        public static ImageArray GetMonsterImageLibrary(int appr)
        {
            switch (appr / 10)
            {
                case 0: 
                    return ImageLib.Monster1;
                case 1:
                    return ImageLib.Monster2;
                case 2:
                    return ImageLib.Monster3;
                case 3:
                    return ImageLib.Monster4;
                case 4:
                    return ImageLib.Monster5;
                case 5:
                    return ImageLib.Monster6;
                case 6:
                    return ImageLib.Monster7;
                case 7:
                    return ImageLib.Monster8;
                case 8:
                    return ImageLib.Monster9;
                case 9:
                    return ImageLib.Monster10;
                case 10:
                    return ImageLib.Monster11;
                case 11:
                    return ImageLib.Monster12;
                case 12:
                    return ImageLib.Monster13;
                case 13:
                    return ImageLib.Monster14;
                case 14:
                    return ImageLib.Monster15;
                case 15:
                    return ImageLib.Monster16;
                case 16:
                    return ImageLib.Monster17;
                case 17:
                    return ImageLib.Monster18;
                case 18:
                    return ImageLib.Monster19;
                case 19:
                    return ImageLib.Monster20;
                case 20:
                    return ImageLib.Monster21;
                case 21:
                    return ImageLib.Monster22;
                case 22:
                    return ImageLib.Monster23;
                case 23:
                    return ImageLib.Monster24;
                case 24:
                    return ImageLib.Monster25;
                default: 
                    return ImageLib.SmallTiles;
            }
        }

        // NOTE: Gets The Offset For Human/Monster - NEEDS FINISHING!
        public static int GetOffset(int appr)
        {
            int npos = appr % 10, nrace = appr / 10;
            switch (nrace)
            {
                case 0: 
                    return npos*230;
                case 1:
                    switch (npos)
                    {
                        case 0:
                        case 1:
                            return npos*230;
                        case 2:
                            return 280;
                        case 3:
                            return 350;
                        case 4:
                            return 700;
                        case 5:
                            return 740;
                        case 6:
                            return 1000;
                    }
                    break;
                case 2:
                case 3:
                case 7:
                case 8:
                case 9:
                case 10:
                case 11:
                case 12:
                case 14:
                case 15:
                case 16:
                    return npos*360;
                case 4:
                    if (npos * 360 == 1) return 600; 
                    return npos*360;
                case 5:
                    return npos*430;
                case 6:
                    return npos*440;
            }
            return 0;
        }

        // NOTE: Gets Offsets For Merchants - NEEDS FINISHING!
        public static int GetMerchantOffset(int appr)
        {
            return 0;
        }
    }


    public struct ActorActions
    {
        public ushort Start;
        public ushort Frame;
        public ushort Skip;
        public ushort AnimationTime;
        public byte UseTick;

        public ActorActions(ushort start, ushort frame, ushort skip, ushort animationtime, byte usetick)
        {
            this.Start = start;
            this.Frame = frame;
            this.Skip = skip;
            this.AnimationTime = animationtime;
            this.UseTick = usetick;
        }
    }

    public sealed class MonsterAction9
    {
        public static ActorActions ActStand = new ActorActions(25, 4, 4, 200, 0);
        public static ActorActions ActWalk = new ActorActions(0, 4, 4, 200, 0);
        public static ActorActions ActAttack = new ActorActions(0, 4, 4, 200, 0);
        public static ActorActions ActCritical = new ActorActions(0, 4, 4, 200, 0);
        public static ActorActions ActStruck = new ActorActions(0, 4, 4, 200, 0);
        public static ActorActions ActDie = new ActorActions(0, 4, 4, 200, 0);
        public static ActorActions ActDeath = new ActorActions(0, 4, 4, 200, 0);
    }

    public class MonsterActor : ActorInformation
    {
        
    }

    public class MerchantActor : ActorInformation
    {
        public void CalculateMerchantFrame()
        {
            BodyOffset = GetMerchantOffset(Appearance);
            Object MerchantAction = GetAnimations(Appearance, Race);

            if (MerchantAction == null)
                return;

            Direction = (byte)(Direction % 3);

            switch (CurrentAction)
            {
                case Common.Global.SM_TURN:
                    if (Appearance == 57)
                    {
                        Direction = 0;
                        //MerchantAction.
                    }
                    break;
            }
        }
    }

    public class HumanActor : ActorInformation
    {
        
    }

}
